package com.fare.taluo.core.domain.crawl.adapter.sub;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.http.HeaderElement;
import org.apache.http.HeaderElementIterator;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.params.CookiePolicy;
import org.apache.http.client.utils.URIUtils;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.message.BasicHeaderElementIterator;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.util.EntityUtils;

import com.fare.taluo.conf.ConfigContainer;
import com.fare.taluo.core.domain.ChannelConst;
import com.fare.taluo.core.domain.crawl.CrawlTaskModel;
import com.fare.taluo.core.domain.crawl.PageErrorResultException;
import com.fare.taluo.core.domain.crawl.adapter.AbstractAdapter;
import com.fare.taluo.core.domain.crawl.adapter.CrawlAdapterFactory;
import com.fare.taluo.core.domain.entity.crawl.FreightPriceEntity;
import com.fare.taluo.util.RegHtmlUtil;

/**
 * 中国国际航空
 * <p>将原来的AirchinaServiceImpl实现代码搬过来先，后面再优化
 *
 */
public class AirchinaAdapter extends AbstractAdapter {
	
	
	private static final String REQUEST_HOST = "et.airchina.com.cn";// 主机
	private static final String REQUEST_PATH = "/InternetBooking/AirLowFareSearchExternal.do";// 路径


	private HttpClient httpClient;
	
	public AirchinaAdapter(CrawlTaskModel taskModel) {
		super(taskModel);
	}

	private URI produceUri(int year, int month, int day,
			String depPort, String arrPort) throws URISyntaxException {

		// 请求参数
		List<NameValuePair> qparams = new ArrayList<NameValuePair>();
		qparams.add(new BasicNameValuePair("tripType", "OW"));
		qparams.add(new BasicNameValuePair("searchType", "FARE"));
		qparams.add(new BasicNameValuePair("flexibleSearch", "false"));
		qparams.add(new BasicNameValuePair("directFlightsOnly", "false"));
		qparams.add(new BasicNameValuePair("fareOptions", "1.FAR.X"));
		qparams.add(new BasicNameValuePair("outboundOption.originLocationCode",
				depPort));
		qparams.add(new BasicNameValuePair(
				"outboundOption.destinationLocationCode", arrPort));
		qparams.add(new BasicNameValuePair("outboundOption.departureDay", day+""));
		qparams.add(new BasicNameValuePair("outboundOption.departureMonth",
				month+""));
		qparams.add(new BasicNameValuePair("outboundOption.departureYear", year+""));
		qparams.add(new BasicNameValuePair("outboundOption.departureTime", "NA"));
		qparams.add(new BasicNameValuePair("guestTypes[0].type", "ADT"));
		qparams.add(new BasicNameValuePair("guestTypes[0].amount", "1"));
		qparams.add(new BasicNameValuePair("guestTypes[1].type", "CNN"));
		qparams.add(new BasicNameValuePair("guestTypes[1].amount", "0"));
		qparams.add(new BasicNameValuePair("pos", "AIRCHINA_CN"));
		qparams.add(new BasicNameValuePair("lang", "zh_CN"));
		qparams.add(new BasicNameValuePair("guestTypes[2].type", "INF"));
		qparams.add(new BasicNameValuePair("guestTypes[2].amount", "0"));

		return URIUtils.createURI("http", REQUEST_HOST, -1,
					REQUEST_PATH, URLEncodedUtils.format(qparams, "UTF-8"),
					null);
	}

	public String getCookies(int year,
			int month, int day, String depPort, String arrPort) throws Exception
			 {
		String cookie = "";
		HttpPost request = new HttpPost(produceUri(year, month, day, depPort,
				arrPort));

		request.setHeader("Accept",
				"Accept	text/html, application/xhtml+xml, */*");
		request.setHeader("Accept-Charset", "GBK,utf-8;q=0.7,*;q=0.3");
		request.setHeader("Accept-Language", "zh-CN");
		request.setHeader("Connection", "keep-Alive");
		request.setHeader(
				"Cookie",
				"current_PoS=AIRCHINA_CN; currentLang=zh_CN");
		request.setHeader("Host", "et.airchina.com.cn");
		request.setHeader(
				"User-Agent",
				"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.142 Safari/535.19");

		try {
			HttpResponse response = httpClient.execute(request, new BasicHttpContext());

			HeaderElementIterator it = new BasicHeaderElementIterator(
					response.headerIterator("Set-Cookie"));
			while (it.hasNext()) {
				HeaderElement elem = it.nextElement();
				if (elem != null && elem.getName().equals("JSESSIONID")) {
					cookie += elem.getName() + "=" + elem.getValue();
				}
				if (elem != null
						&& elem.getName().equals("BIGipServerWeb_http")) {
					cookie += "; " + elem.getName() + "=" + elem.getValue();
				}
			}


		}finally {
			if(request != null) request.releaseConnection();
		}
		return cookie;
	}

	public Object fetch(String url) throws Exception {

		Date gradDate = DateUtils.parseDate(taskModel.getFlightDate(), "yyyy-MM-dd");
		Calendar cal = Calendar.getInstance();
		cal.setTime(gradDate);

		String resHtml = "";
		HttpGet request = null;
		HttpEntity entity = null;
		//String cookie="JSESSIONID=2E79EA48FDFC89EA354FDF0625C67116; current_PoS=AIRCHINA_CN; BIGipServerWeb_http=4228062892.20480.0000; s_sess=%20s_cc%3Dtrue%3B%20s_sq%3D%3B; currentLang=zh_CN; mbox=session#1355925804659-307507#1355927871|check#true#1355926071";
		try {
			httpClient = super.getHttpClient(); 
			request = new HttpGet(getUrl());
			httpClient.getParams().setParameter(ClientPNames.COOKIE_POLICY,
					CookiePolicy.BEST_MATCH);
			
			request.getParams().setParameter(ClientPNames.COOKIE_POLICY,
					CookiePolicy.BEST_MATCH);

			request.setHeader("Accept",
					"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
			request.setHeader("Accept-Charset", "GBK,utf-8;q=0.7,*;q=0.3");
			request.setHeader("Accept-Language", "zh-CN,zh;q=0.8");
			request.setHeader("Connection", "keep-alive");
			request.setHeader("Cookie",
					getCookies(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH)+1, cal.get(Calendar.DATE), taskModel.getFromCity(), taskModel.getToCity()));
//			request.setHeader("Cookie",
//					cookie);
			request.setHeader("Host", "et.airchina.com.cn");
			request.setHeader(
					"User-Agent",
					"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.97 Safari/537.11");
			HttpResponse response = httpClient.execute(request);
			entity = response.getEntity();
			

			if (entity != null) {
				

				// 将源码流保存在一个byte数组当中，因为可能需要两次用到该流，
				byte[] bytes = EntityUtils.toByteArray(entity);
				String charSet = "";

				// 如果头部Content-Type中包含了编码信息，那么我们可以直接在此处获取
				charSet = EntityUtils.getContentCharSet(entity);

				//System.out.println("In header: " + charSet);
				// 如果头部中没有，那么我们需要 查看页面源码，这个方法虽然不能说完全正确，因为有些粗糙的网页编码者没有在页面中写头部编码信息
				if (charSet == "") {
					String regEx = "(?=<meta).*?(?<=charset=[\\'|\\\"]?)([[a-z]|[A-Z]|[0-9]|-]*)";
					Pattern p = Pattern.compile(regEx, Pattern.CASE_INSENSITIVE);

					Matcher m = p.matcher(new String(bytes)); // 默认编码转成字符串，因为我们的匹配中无中文，所以串中可能的乱码对我们没有影响
					
					if (m.groupCount() == 1) {
						charSet = m.group(1);
					} else {
						charSet = "";
					}
				}

				if (charSet != null) {
					if ("".equals(charSet.trim())) {
						charSet = "utf-8";

					}
				} else {
					charSet = "utf-8";
				}
				resHtml=new String(bytes, charSet);
			}
		}finally{
			if(request != null) request.releaseConnection();
			request = null;
			entity = null;

		}
		
		int lenght = resHtml.toString().getBytes().length;//设置流量统计
		return resHtml;
	}

	/**
	 * 从html字符串解析机票数据
	 * 
	 * @param html
	 * @return
	 * @throws Exception 
	 */
	public List<Object> paraseToVo(Object fetchObject) throws Exception {
	       
		List<Object> results = new ArrayList<Object>();
		
		List<String> shtml=this.getMlementContentReturn((String)fetchObject);
		if(shtml != null){
			for (Iterator<String> iterator = shtml.iterator(); iterator.hasNext();) {
				String html = iterator.next();
				//抓取价格
				List<String> lowprice=RegHtmlUtil.retrieveLinks(html,"\"flightSelectGr_0_([\\d]+?)\\\\\"\\\\u003e([^\\t]+?)\\\\u",2);//ok
				String lowerPrice=null;
				int m=0;
				for (int i=0;i<lowprice.size();i++) {
					String s = (String) lowprice.get(i);
					Integer l=Integer.parseInt(s.replaceAll(",", ""));
					if(i==0){
						m=l;
					}
					if(m>l){
						m=l;
					}
				}
				lowerPrice=m+"";
				if(StringUtils.isEmpty(lowerPrice)){
					continue;
				}
				///航班编号
				String flightNo=RegHtmlUtil.regStr(html,";return false;\\\\\"\\\\u003e([\\w]+?)\\\\u003c",1);//OK
				if(StringUtils.isEmpty(flightNo)){
					continue;
				}
				//航班类型型号
				String flightTypeNos=RegHtmlUtil.regStr(html,"do\\?equipmentType=([\\w]{2,6})\\\\\'",1); ///OK
				if(StringUtils.isEmpty(flightTypeNos)){
					continue;
				}
				///起飞时间
				String depTimes=RegHtmlUtil.regStr(html,"div\\s*\\\\u003e([\\d][\\d][:][\\d][\\d])\\\\u003c/div\\\\u",1);//OK
				if(StringUtils.isEmpty(depTimes)){
					continue;
				}
				//到达时间
				String arrTimes=RegHtmlUtil.regStr(html,"colArrive\\\\\"\\\\u003e\\\\n"+
	      "\\\\t\\\\t\\\\t\\\\u003cdiv\\s*\\\\u003e([\\d][\\d][:][\\d][\\d])\\\\u003c/div\\\\u",1);//OK
				if(StringUtils.isEmpty(arrTimes)){
					continue;
				}
	
				results.add(CrawlAdapterFactory.createPlaneInfo(taskModel, "CA", "国航", "中国国际航空公司", 
						 depTimes.trim(), arrTimes.trim(), flightNo,
						lowerPrice.trim(), null, 
						null, flightTypeNos));
			}
		}
		return results;
	}
	/**
	 * 得到每一行的记录
	 * @param shtml
	 * @return
	 */
	private List<String> getMlementContentReturn(String sHtml){
		return RegHtmlUtil.retrieveLinks(RegHtmlUtil.regStr(sHtml, "tdGroupData\\[0\\]\\s*=([^>]+)\\};",1,Pattern.CASE_INSENSITIVE|Pattern.COMMENTS|Pattern.DOTALL),
				"\"([-]*[\\d]+)\":\\s*\"\\\\u(.*?)tbody\\\\u003e\\\\n\\\\t\\\\t\\\\t\\\\t\"",2,Pattern.DOTALL);//ok
	}
	

	@Override
	public String getUrl() throws Exception {
		return "http://et.airchina.com.cn/InternetBooking/AirLowFareSearchExt.do";
	}

	@Override
	public boolean validateFetch(Object fetchObject) throws Exception {
		if(fetchObject == null){
			return false;
		}else if(fetchObject instanceof String){
			if(((String)fetchObject).length() < 2000){
				throw new PageErrorResultException("抓取的数据不正确(长度少于2000)");
			}
			//验证字符串里是否包含抓取的错误信息
			//验证字符串里是否包含抓取的错误信息
			String result = RegHtmlUtil.regStr((String)fetchObject, this.getErrors());
			if(result != null){
				throw new PageErrorResultException(result);
			}
		}
		return true;
	}	
	
	private List<String> getErrors(){
		List<String> airChinaErrors = new ArrayList<String>();
		airChinaErrors.add("404 Not Found");
		airChinaErrors.add("<title>提示</title>");
		return airChinaErrors;
	}
	
	public static void  main(String[] arg) throws Exception{

		CrawlTaskModel taskModel = new CrawlTaskModel();
		taskModel.setGrabChannelId(ChannelConst.CHANNEL_AIRCHINA);
		taskModel.setFromCity("CAN");
		taskModel.setFromCityName("广州");
		taskModel.setToCity("PEK");
		taskModel.setToCityName("北京");
		taskModel.setFlightDate("2013-05-31");
		try{
			System.out.println("start crawl......");
			ConfigContainer.getInstance().register("com.fare.taluo.core.domain.crawl.CrawlPropertiesLoader");
			AirchinaAdapter c = new AirchinaAdapter(taskModel);
			Object fecthObject = c.fetch(null);
			List<Object> results = c.paraseToVo(fecthObject);
			
			System.out.println("paraseToVo finish:"+results.size());
			for (Object o : results) {
				FreightPriceEntity p = (FreightPriceEntity)o;
				System.out.println(p.toString());
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			System.out.println("finish .......");
			Runtime.getRuntime().exit(1);
		}
	}
}
